﻿// ******************************************************************************
// Developed by Oguz Demirel
// Date: March 17, 2010
// ******************************************************************************
namespace BulkListActions
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Web;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;

    public abstract class CustomHandlerBase : IHttpHandler
    {
        private Dictionary<string, int> metadata = new Dictionary<string, int>();
        protected Dictionary<string, string> commonFields = new Dictionary<string, string>();
        protected int itemCount = 0;
        private int nOfItems = 0;
        protected string referrer = "";

        // This method CAN be overridden by deriving classes
        // since it's declared as virtual here
        public virtual void ProcessRequest(HttpContext context)
        {
            // Get querystring from context
            NameValueCollection queryString = context.Request.QueryString;

            // Clear metadata dictionary before using
            metadata.Clear();

            // Get web obj from context
            SPWeb web = SPContext.Current.Web;

            // Parse and check qs parameters
            string strList = queryString["List"];
            string strView = queryString["View"];
            referrer = queryString["referrer"];
            string strItem = queryString["Item"];

            // Check qs parameters for any errors
            Helper.CheckQueryString(queryString);

            // Get list obj from web
            SPList list = web.Lists[new Guid(strList)];

            
            // Get number of content types of this list
            
            string[] items = strItem.Split(new char[] { ',' });
            nOfItems = itemCount = items.Length;

            // There are selected items
            if (!string.IsNullOrEmpty(strItem))
            {
                // Loop for each selected item
                foreach (string itemID in strItem.Split(new char[] { ',' }) )
                {
                    int num;
                    if (int.TryParse(itemID, out num))
                    {
                        web.AllowUnsafeUpdates = true;

                        try
                        {
                            // Get selected item
                            SPListItem itemById = list.GetItemById(num);

                            // *************************************
                            // WRITE YOUR CODE here for custom action
                            // Process selected items here 
                            // *************************************

                            // Get common metadata field keys
                            GetCommonMetadataFields(itemById);

                            // At this point, all COMMON metadata keys
                            // are listed in 'commonFields' dictionary.

                            ProcessItem(itemById);
                            

                        } // end - try 
                        catch (Exception ex)
                        {
                            SPUtility.TransferToErrorPage(ex.Message + " {0} {1}", "Click here to go back to the list.", referrer);
                        }
                        finally
                        {
                            web.AllowUnsafeUpdates = false;
                        }

                    } // end - if

                } // end - foreach
            }
            else
            {
                // No items selected
                // Display error
                SPUtility.TransferToErrorPage("No items selected. {0} {1}", "Click here to go back to the list.", referrer);
            }

            // Go back to list once all selected items are processed.
            if (!string.IsNullOrEmpty(referrer))
                context.Response.Redirect(referrer, true);

        }

        // This method CAN be overridden by deriving classes
        // since it's declared as virtual here
        public virtual bool IsReusable
        {
            get
            {
                return true;
            }
        }

        // This method MUST be implemented by deriving classes
        // since it's declared as abstract
        public abstract void ProcessItem(SPListItem item);

        // This method gets metadata values of an item
        // based on its content type
        private void GetCommonMetadataFields(SPListItem item)
        { 
            // **************************************
            // NOTE: This method will ONLY get COMMON fields
            // of selected documents' CTs
            // **************************************

            // Keep count of processed CTs
            itemCount--;
            
            // Get item's CT
            SPContentType ct = item.ContentType;
            if (ct != null)
            {
                

                // Get metadata fields
                foreach (SPField field in ct.Fields)
                {
                    // Skip filename and content type
                    if (field.InternalName == "FileLeafRef" || field.InternalName == "ContentType")
                        continue;
                    
                    if (!field.Hidden && !field.ReadOnlyField && field.Type != SPFieldType.Attachments)
                    {
                        // This metadata key appears for the first time
                        // Set it to 0
                        if (metadata.ContainsKey(field.InternalName) == false)
                            // Add field names to dictionary
                            // Values will be provided by user
                            metadata.Add(field.InternalName, 1);
                        // This metadata key appears again
                        // Increment its count
                        else
                            metadata[field.InternalName]++;
                    }

                } // end - foreach

            } // end - if

            // All items are processed.
            // Now, determine common fields using values
            // in metadata dictionary
            if (itemCount == 0)
            {
                // Loop thru all fields
                foreach (var pair in metadata)
                {
                    // If value for current pair is less than # of items,
                    // then this simply means that field is NOT a common field.
                    // If it is equal, then it's COMMON field for all CTs used,
                    // and we need to store that field internal name.
                    if (pair.Value == nOfItems)
                        commonFields.Add(pair.Key, "");

                    
                } // end - foreach

            } // end - if 
        
        } // end - GetMetadata

    } // end - abstract class CustomHandlerBase
}
